`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    15:50:18 03/24/2012 
// Design Name: 
// Module Name:    PcieCore 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module PcieCore #(
  parameter SIMULATION                  = "FALSE", // Indicates whether SIM or HW
  parameter LANES                       = 4,        // Number of PCIe Lanes
  parameter        HEADER_TYPE = 8'h01,
  parameter        IS_SWITCH = "TRUE",
  parameter        CLASS_CODE = 24'h060400,
  parameter        PCIE_CAP_DEVICE_PORT_TYPE = 4'b0000,
  parameter        UPSTREAM_FACING = "TRUE",
  parameter        DISABLE_BAR_FILTERING = "TRUE",
  parameter        ENABLE_RX_TD_ECRC_TRIM = "TRUE",
  parameter        BAR0 = 32'h00000000,
  parameter        BAR1 = 32'h00000000,
  parameter        BAR2 = 32'h00FFFFFF,
  parameter        BAR3 = 32'hFFFFFFFF,
  parameter        BAR4 = 32'hFFFFFFFF,
  parameter        BAR5 = 32'hFFFFFFFF
)(
  input PCIE_CLK,                                              // PCIe System Clock - P
  input PCIE_RST,                                              // PCIe System Reset

  output [LANES-1:0] PCIE_TXn,
  output [LANES-1:0] PCIE_TXp,
  input  [LANES-1:0] PCIE_RXn,
  input  [LANES-1:0] PCIE_RXp,

  input               CLK,
  input               RST,
  
  input               tx_tvalid,
  output              tx_tready,
  input   [127:0]     tx_tdata,
  input   [3:0]       tx_tstrb,
  input               tx_tlast,
      
  output              rx_tvalid,
  input               rx_tready,
  output  [127:0]     rx_tdata,
  output  [3:0]       rx_tstrb,
  output              rx_tlast,

  input   [31:0]  S_AWADDR,
  input           S_AWVALID,
  output          S_AWREADY,
  input   [31:0]  S_WDATA,
  input   [3:0]   S_WSTRB,
  input           S_WVALID,
  output          S_WREADY,
  output  [1:0]   S_BRESP,
  output          S_BVALID,
  input           S_BREADY,
  input   [31:0]  S_ARADDR,
  input           S_ARVALID,
  output          S_ARREADY,
  output  [31:0]  S_RDATA,
  output  [1:0]   S_RRESP,
  output          S_RVALID,
  input           S_RREADY,

  input           drp_clk,
  input           drp_den,
  input           drp_dwe,
  input   [8:0]   drp_daddr,
  input   [15:0]  drp_di,
  output          drp_drdy,
  output  [15:0]  drp_do,
  
  output reg [31:0]   CfgDo,
  input   [31:0]      CfgDi,
  input   [3:0]       CfgBe,
  input   [9:0]       CfgAddr,
  input               CfgWe,
  input               CfgReq,
  output reg          CfgAck,
  
  output              link_up  
);

  assign S_AWREADY = 1'b0;
  assign S_WREADY = 1'b0;
  assign S_BRESP = 2'b0;
  assign S_BVALID = 1'b0;
  assign S_ARREADY = 1'b0;
  assign S_RDATA = 32'b0;
  assign S_RRESP = 2'b0;
  assign S_RVALID = 1'b0;
  
  wire [3:0]  tx_tuser = 4'b0; //{t_src_dsc, tx_str,  tx_err_fwd, tx_ecrc_gen}

  wire        rx128_tvalid;
  wire        rx128_tready;
  wire [127:0] rx128_tdata;
  wire [3:0]  rx128_tstrb;
  wire        rx128_tlast;
  
  wire        tx128_tvalid;
  wire        tx128_tready;
  wire [127:0] tx128_tdata;
  wire [3:0]  tx128_tstrb;
  wire        tx128_tlast;

  wire        rx64_tvalid;
  wire        rx64_tready;
  wire [63:0] rx64_tdata;
  wire [7:0]  rx64_tkeep;
  wire        rx64_tlast;
  
  wire        tx64_tvalid;
  wire        tx64_tready;
  wire [63:0] tx64_tdata;
  wire [7:0]  tx64_tkeep;
  wire        tx64_tlast;

  wire [1:0]  rx64_tstrb = {rx64_tkeep[4], rx64_tkeep[0]};
  wire [1:0]  tx64_tstrb;
  assign tx64_tkeep = {{4{tx64_tstrb[1]}}, {4{tx64_tstrb[0]}}};
  
  wire user_clk;
  wire user_rst;
  wire fifo_rst = user_rst || RST;
  
  localparam
    IDLE = 0,
    READ = 1,
    WRITE = 2,
    ACK = 3;
    
  reg [2:0] rCfgState, sCfgState;
  reg rCfgReq;
  
  wire  [31:0]      cfg_do;
  wire  [31:0]      cfg_di = CfgDi;
  wire  [3:0]       cfg_byte_en = CfgBe;
  wire              cfg_wr_en = (rCfgState == WRITE);
  wire              cfg_rd_en = (rCfgState == READ);
  wire  [9:0]       cfg_dwaddr = CfgAddr;
  wire              cfg_rd_wr_done;
  
  always @(posedge user_clk)
  begin
    rCfgReq <= CfgReq && !CfgAck;
    if (cfg_rd_wr_done)
      CfgDo <= cfg_do;
  end
  
  always @(posedge CLK)
  begin
    if (RST)
      CfgAck <= 1'b0;
    else
    begin
      if (CfgAck)
        CfgAck <= 1'b0;
      else if (rCfgState == ACK)
        CfgAck <= 1'b1;
    end
  end
  
  always @(posedge user_clk)
  begin
    if (user_rst)
      rCfgState <= IDLE;
    else
      rCfgState <= sCfgState;
  end
  
  always @*
  begin
    sCfgState <= rCfgState;
    case (rCfgState)
      IDLE:
        if (rCfgReq)
        begin
          if (CfgWe)
            sCfgState <= WRITE;
          else
            sCfgState <= READ;
        end
      READ:
        if (cfg_rd_wr_done)
          sCfgState <= ACK;
      WRITE:
        if (cfg_rd_wr_done)
          sCfgState <= ACK;
      ACK:
        if (!rCfgReq)
          sCfgState <= IDLE;
    endcase
  end

  axis_async_fifo128
  rx_fifo(
    .rst      (fifo_rst),
  
    .s_clk    (user_clk),
    .s_tvalid (rx128_tvalid),
    .s_tready (rx128_tready),
    .s_tdata  (rx128_tdata),
    .s_tstrb  (rx128_tstrb),
    .s_tlast  (rx128_tlast),

    .m_clk    (CLK),
    .m_tvalid (rx_tvalid),
    .m_tready (rx_tready),
    .m_tdata  (rx_tdata),
    .m_tstrb  (rx_tstrb),
    .m_tlast  (rx_tlast));

  axis_async_fifo128
  tx_fifo(
    .rst      (fifo_rst),
    
    .s_clk    (CLK),
    .s_tvalid (tx_tvalid),
    .s_tready (tx_tready),
    .s_tdata  (tx_tdata),
    .s_tstrb  (tx_tstrb),
    .s_tlast  (tx_tlast),
    
    .m_clk    (user_clk),
    .m_tvalid (tx128_tvalid),
    .m_tready (tx128_tready),
    .m_tdata  (tx128_tdata),
    .m_tstrb  (tx128_tstrb),
    .m_tlast  (tx128_tlast));

  axis_double_width #(
    .DWIDTH     (64),
    .KWIDTH     (2))
  rx_width_conv (
    .clk        (user_clk),
    .rst        (user_rst),
    
    .s_tvalid  (rx64_tvalid),
    .s_tready  (rx64_tready),
    .s_tdata   (rx64_tdata),
    .s_tkeep   (rx64_tstrb),
    .s_tlast   (rx64_tlast),
  
    .m_tvalid  (rx128_tvalid),
    .m_tready  (rx128_tready),
    .m_tdata   (rx128_tdata),
    .m_tkeep   (rx128_tstrb),
    .m_tlast   (rx128_tlast));
  
  axis_half_width #(
    .DWIDTH     (128),
    .KWIDTH     (4))
  tx_width_conv (
    .clk        (user_clk),
    .rst        (user_rst),
    
    .s_tvalid  (tx128_tvalid),
    .s_tready  (tx128_tready),
    .s_tdata   (tx128_tdata),
    .s_tkeep   (tx128_tstrb),
    .s_tlast   (tx128_tlast),
  
    .m_tvalid  (tx64_tvalid),
    .m_tready  (tx64_tready),
    .m_tdata   (tx64_tdata),
    .m_tkeep   (tx64_tstrb),
    .m_tlast   (tx64_tlast));

  v6_pcie_v2_5 #(
    .PL_FAST_TRAIN                  (SIMULATION),
    .LINK_CAP_MAX_LINK_WIDTH        (LANES),
    .LINK_CAP_MAX_LINK_SPEED        (4'h1),
    .HEADER_TYPE                    (HEADER_TYPE),
    .IS_SWITCH                      (IS_SWITCH),
    .CLASS_CODE                     (CLASS_CODE),
    .PCIE_CAP_DEVICE_PORT_TYPE      (PCIE_CAP_DEVICE_PORT_TYPE),
    .UPSTREAM_FACING                (UPSTREAM_FACING),
    .DISABLE_BAR_FILTERING          (DISABLE_BAR_FILTERING),
    .ENABLE_RX_TD_ECRC_TRIM         (ENABLE_RX_TD_ECRC_TRIM),
    .BAR0                           (BAR0),
    .BAR1                           (BAR1),
    .BAR2                           (BAR2),
    .BAR3                           (BAR3),
    .BAR4                           (BAR4),
    .BAR5                           (BAR5)
    )
  pcie(
    .pci_exp_txn                    (PCIE_TXn),
    .pci_exp_txp                    (PCIE_TXp),
    .pci_exp_rxn                    (PCIE_RXn),
    .pci_exp_rxp                    (PCIE_RXp),

    .user_clk_out                   (user_clk),
    .user_reset_out                 (user_rst),
    .user_lnk_up                    (link_up),
              
    .tx_buf_av                      (),
    .tx_err_drop                    (),
    .tx_cfg_req                     (),
    .s_axis_tx_tready               (tx64_tready),
    .s_axis_tx_tdata                (tx64_tdata),
    .s_axis_tx_tkeep                (tx64_tkeep),
    .s_axis_tx_tuser                (tx_tuser),
    .s_axis_tx_tlast                (tx64_tlast),
    .s_axis_tx_tvalid               (tx64_tvalid),
    .tx_cfg_gnt                     (1'b1),
              
    .m_axis_rx_tdata                (rx64_tdata),
    .m_axis_rx_tkeep                (rx64_tkeep),
    .m_axis_rx_tlast                (rx64_tlast),
    .m_axis_rx_tvalid               (rx64_tvalid),
    .m_axis_rx_tready               (rx64_tready),
    .m_axis_rx_tuser                (),
    .rx_np_ok                       (1'b1),
              
    .fc_cpld                        (),
    .fc_cplh                        (),
    .fc_npd                         (),
    .fc_nph                         (),
    .fc_pd                          (),
    .fc_ph                          (),
    .fc_sel                         (3'b100),
              
    .cfg_status                     (),
    .cfg_command                    (),
    .cfg_dstatus                    (),
    .cfg_dcommand                   (),
    .cfg_lstatus                    (),
    .cfg_lcommand                   (),
    .cfg_dcommand2                  (),
    .cfg_pcie_link_state            (),

    .cfg_pmcsr_pme_en               (),
    .cfg_pmcsr_powerstate           (),
    .cfg_pmcsr_pme_status           (),

    .cfg_di                         (cfg_di),
    .cfg_byte_en                    (cfg_byte_en),
    .cfg_dwaddr                     (cfg_dwaddr),
    .cfg_wr_en                      (cfg_wr_en),
    .cfg_rd_en                      (cfg_rd_en),
    .cfg_do                         (cfg_do),
    .cfg_rd_wr_done                 (cfg_rd_wr_done),

    .cfg_err_ecrc                   (1'b0),
    .cfg_err_ur                     (1'b0),
    .cfg_err_cpl_timeout            (1'b0),
    .cfg_err_cpl_unexpect           (1'b0),
    .cfg_err_cpl_abort              (1'b0),
    .cfg_err_posted                 (1'b0),
    .cfg_err_cor                    (1'b0),
    .cfg_err_tlp_cpl_header         (48'b0),
    .cfg_err_cpl_rdy                (),
    .cfg_err_locked                 (1'b0),

    .cfg_trn_pending                (1'b0),

    .cfg_dsn                        (64'b0),

    .cfg_interrupt                  (1'b0),
    .cfg_interrupt_rdy              (),
    .cfg_interrupt_assert           (1'b0),
    .cfg_interrupt_di               (8'b0),
    .cfg_interrupt_do               (),
    .cfg_interrupt_mmenable         (),
    .cfg_interrupt_msienable        (),
    .cfg_interrupt_msixenable       (),
    .cfg_interrupt_msixfm           (),

    .cfg_to_turnoff                 (),
    .cfg_turnoff_ok                 (1'b0),
    .cfg_bus_number                 (),
    .cfg_device_number              (),
    .cfg_function_number            (),
    .cfg_pm_wake                    (1'b0),
        
    .pl_directed_link_change        (2'b0),
    .pl_directed_link_width         (2'b0),
    .pl_directed_link_speed         (1'b0),
    .pl_directed_link_auton         (1'b0),
    .pl_upstream_prefer_deemph      (1'b0),
    .pl_sel_link_rate               (),
    .pl_sel_link_width              (),
    .pl_ltssm_state                 (),
    .pl_lane_reversal_mode          (),
    .pl_link_upcfg_capable          (),
    .pl_link_gen2_capable           (),
    .pl_link_partner_gen2_supported (),
    .pl_initial_link_width          (),
    .pl_received_hot_rst            (),
    
    .pcie_drp_clk                   (drp_clk  ),
    .pcie_drp_den                   (drp_den  ),
    .pcie_drp_dwe                   (drp_dwe  ),
    .pcie_drp_daddr                 (drp_daddr),
    .pcie_drp_di                    (drp_di),
    .pcie_drp_do                    (drp_do),
    .pcie_drp_drdy                  (drp_drdy ),

    .sys_clk                        (PCIE_CLK),
    .sys_reset                      (PCIE_RST)
    );

endmodule
